package haxe.util;
import Type.ValueType;

interface Comparator<T>
{
	public function compare(o1:T, o2:T):Int;
	public function equals(o1:T, o2:T):Bool;
}

interface Comparable<T>
{
	public function compareTo(o:T):Int;
}

class Comparators<T>
{
	public static function getComparator<T>( o:Dynamic ):Comparator<T>
	{
		return untyped 
		{
			switch( Type.typeof(o) )
			{
				case TBool : BoolComparator.getInstance();
				case TInt  : IntComparator.getInstance();
				case TFloat : FloatComparator.getInstance();
				case TObject :
					if ( Type.getClass(o) == String ) 
						Collator.getInstance();
					else
					{
						NaturalComparator.getInstance();
					};
				default : NaturalComparator.getInstance();
			}
		}
	}
}

class IntComparator implements Comparator<Int>
{
	private static var _inst:IntComparator;
	
	private function new(){}
	
	public static function getInstance():Comparator<Int>
	{
		if ( _inst == null ) _inst = new IntComparator();
		return _inst;
	}
	
	public function compare( o1:Int, o2:Int ):Int
	{
		return if( o1 > o2 ) 1 else if( o1 < o2 ) -1 else 0;
	}
	
	
	public function equals(o1:Int, o2:Int ):Bool
	{
		return o1 == o2;
	}
}

class FloatComparator implements Comparator<Float>
{
	private static var _inst:FloatComparator;
	
	private function new(){}
	
	public static function getInstance():Comparator<Float>
	{
		if ( _inst == null ) _inst = new FloatComparator();
		return _inst;
	}
	
	public function compare(o1:Float, o2:Float ):Int
	{
		return if( o1 > o2 ) 1 else if( o1 < o2 ) -1 else 0;
	}
	
	
	public function equals(o1:Float, o2:Float ):Bool
	{
		return o1 == o2;
	}
}

class BoolComparator implements Comparator<Bool>
{
	private static var _inst:Dynamic;
	
	private function new(){}
	
	public static function getInstance():Comparator<Bool>
	{
		if ( _inst == null ) _inst = new BoolComparator();
		return _inst;
	}
	
	public function compare( o1:Bool, o2:Bool ):Int
	{
		return if ( o1 && o2 )
		{
			0;// true & true
		}
		else
		{
			if ( o1 || o2 )
				if( o1 ) 1 else -1;
			else
				0;// false & false
		}
	}
	
	public function equals( o1:Bool, o2:Bool ):Bool
	{
		return ( o1 == o2 );
	}
}

class Collator implements Comparator<String>
{
	private static var _inst:Collator;
	
	private function new(){}
	
	public static function getInstance():Comparator<String>
	{
		if ( _inst == null ) _inst = new Collator();
		return _inst;
	}
	
	public function compare( o1:String, o2:String ):Int
	{
		return if( o1 > o2 ) 1 else if( o1 < o2 ) -1 else 0;//tmp
	}
	
	public function equals( o1:String, o2:String ):Bool
	{
		return o1 == o2;
	}
}

class NaturalComparator implements Comparator<Dynamic>
{
	private static var _inst:NaturalComparator;
	
	private function new(){}
	
	public static function getInstance():Comparator<Dynamic>
	{
		if ( _inst == null ) _inst = new NaturalComparator();
		return _inst;
	}
	
	public function compare( o1:Dynamic, o2:Dynamic ):Int
	{
		return o1.compareTo(o2);
	}
	
	public function equals( o1:Dynamic, o2:Dynamic ):Bool
	{
		return o1.compareTo(o2) == 0;
	}
}